// Copyright (c) 2010 Manuel Peinado Gallego <manuel.peinado@gmail.com>
// Distributed under the MIT license

#include "stdafx.h"

#if 0

#include "WorldBuilder.h"
#include "Collada.h"

#define NO_LIBXML
#include <FCollada.h>
#include <FCDocument\FCDocument.h>
#include <FCDocument\FCDAsset.h>
#include <FCDocument\FCDLibrary.h>
#include <FCDocument\FCDGeometryMesh.h>
#include <FCDocument\FCDGeometry.h>
#include <FCDocument\FCDGeometryPolygons.h>
#include <FCDocument\FCDGeometrySource.h>
#include <FCDocument\FCDSceneNode.h> 
#include <FCDocument\FCDLight.h> 
#include <FCDocument\FCDMaterial.h> 
#include <FCDocument\FCDEffect.h> 
#include <FCDocument\FCDEffectStandard.h> 
#include <FCDocument\FCDGeometryInstance.h>
#include <FCDocument\FCDTexture.h>
#include <FCDocument\FCDMaterialInstance.h>
#include <FCDocument\FCDGeometryPolygonsInput.h>
#include <FCDocument\FCDGeometryPolygonsTools.h>
#include <FUtils\FUObject.h>
#include <FCDocument\FCDImage.h>
#include "DevIL.h"
#include "Texture.h"
#include "LightNode.h"
#include "NodeManager.h"
#include "MeshNode.h"



bool isZUp;

typedef std::map<Mesh*, std::wstring> PolysToMatName;
PolysToMatName m_polyMatNames;

// structures to store geometries that we will be used
std::vector<ref<Mesh> > m_meshes;
std::map<Mesh*, std::string> m_meshIds;

// structures to store lights
std::vector<ref<LightParams> > m_ptrs_lights;
int m_num_lights;

// materials
typedef std::map<std::wstring, std::wstring> StringToString;
StringToString m_materialNameTable;

// textures
std::vector<ref<Texture> > m_textures;
ref<Texture> getTextureByName(const std::wstring& name)
{
    ref<Texture> result;
    for(size_t i = 0; i < m_textures.size(); ++i)
    {
        if(m_textures[i]->getName() == name)
        {
            result = m_textures[i];
            break;
        }
    }
    return result;
}

std::auto_ptr<Mesh> convertPolygonSet(FCDGeometryPolygons& fcdSet);
std::auto_ptr<Texture> convertTexture(FCDImage* image);
std::auto_ptr<Mesh> convertMesh(FCDGeometryMesh* fcdMesh);

// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = 

std::auto_ptr<Texture> convertTexture(FCDImage* image)
{
    std::wstring fileName = image->GetFilename().c_str();
    return std::auto_ptr<Texture>(new Texture(fileName));
}

// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = 

std::auto_ptr<Mesh> convertMesh(FCDGeometryMesh* fcdMesh)
{
    std::auto_ptr<Mesh> result(new Mesh);

    // triangulate this mesh if it was not triangulated
    if(!fcdMesh->IsTriangles())
    {
        FCDGeometryPolygonsTools::Triangulate(fcdMesh);
    }

    // create my own polygons
    size_t nbPolys = fcdMesh->GetPolygonsCount();
    for(size_t i = 0; i < nbPolys; ++i) 
    {
        result->addPolygonSet(
            convertPolygonSet(*fcdMesh->GetPolygons(i)));
    }

    //// retrieve vertex
    //source = mesh->FindSourceByType(FUDaeGeometryInput::POSITION);
    //// offset
    //stride=source->GetSourceStride();
    ////  read number of vertices
    //nbVertices=(int) source->GetSourceData().size() / stride;
    //// read vertex from fcollada, and copy to my structures
    //for (i=0;i<nbVertices; i++) {
    //	//p=&source_vertex->GetSourceData().at(i*3);
    //	p=&source->GetSourceData()[i*3];
    //	m_ptr_vertices.push_back(new gx::Vec3f(p[0],p[1],p[2]));
    //}
    //// do the same for normals, if they are present
    //source = mesh->FindSourceByType(FUDaeGeometryInput::NORMAL);
    //if (source!=NULL) {
    //	m_hasNormals=true;
    //	stride=source->GetSourceStride();
    //	m_num_normals=(int) source->GetSourceData().size() / stride;
    //	for (i=0;i<m_num_normals; i++) {
    //		p=&source->GetSourceData()[i*3];
    //		m_ptr_normals.push_back(new gx::Vec3f(p[0],p[1],p[2]));
    //	}
    //} else {
    //	m_hasNormals=false;
    //}
    //// at this moment we create just ONE texture channel
    ////m_num_texture_channels=1;
    ////m_ptr_texture_channels.push_back(new CCLTextureChannel() );
    ////// count texture channels
    //////m_num_texture_channels=0;
    //////for (i=0; i<mesh->GetSourceCount(); i++) {
    //////	source=mesh->GetSource(i);
    //////	if (source->GetSourceType()==FUDaeGeometryInput::TEXCOORD)
    //////		fstd::string n=source->GetName();
    //////		m_num_texture_channels++;		
    //////	
    //////}
    //// create 
    ////// do the same for texcture coordinates
    ////source = mesh->FindSourceByType(FUDaeGeometryInput::TEXCOORD);
    ////stride=source->GetSourceStride();
    ////int num_texture_coordinates=(int) source->GetSourceData().size() / stride;
    ////for (i=0;i<num_texture_coordinates; i++) {
    ////	p=&source->GetSourceData()[i*3];
    ////	//m_ptr_texture_coordinates.push_back(new gx::Vec3f(p[0],p[1],p[2]));
    ////	m_ptr_texture_channels[0]->AddTextureCoordinate( new gx::Vec3f(p[0],p[1],p[2]) );
    ////}
    return result;
}

// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = 

std::auto_ptr<PolygonSet> convertPolygonSet(FCDGeometryPolygons& fcdSet)
{
    // We don't need this
    // m_mesh_id = fcdSet.GetParent()->GetDaeId().c_str();

    std::auto_ptr<PolygonSet> result(new PolygonSet);
    std::vector<gx::Vec3f> vertices;

    // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = 
    // Vertices

    // indices to vertex
    FCDGeometryPolygonsInput* input = 
        fcdSet.FindInput(FUDaeGeometryInput::POSITION);
    uint32* indices = input->GetIndices();
    
    size_t nbVertices = input->GetIndexCount();
    
    // source of vertex
    FCDGeometrySource* source 
        = fcdSet.GetParent()->FindSourceByType(FUDaeGeometryInput::POSITION);

    // allocate memory for triangles and its vertex (a triangle has 3 vertex)
    vertices.resize(nbVertices);
    
    // look for vertices using indices; 3 contiguous vertex form a triangle
    for(size_t i = 0; i < nbVertices; ++i) 
    {
        // a vertex index
        uint32 index = indices[i];
    
        // a vertex values from it index
        float* p = &source->GetData()[index*3];
        vertices[i] = gx::Vec3f(p[0], p[1], p[2]);
    }
    result->setVertices(vertices);

    // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = 
    // Normals

    // source of normals
    source = fcdSet.GetParent()->FindSourceByType(FUDaeGeometryInput::NORMAL);

    // maybe they are not present
    if(source != NULL) 
    {
        // indices
        input = fcdSet.FindInput(FUDaeGeometryInput::NORMAL);
        indices = input->GetIndices();

        // allocate memory for triangles and its vertex (a triangle has 3 vertex)
        std::vector<gx::Vec3f> normals(nbVertices);
        
        // look for vertices using indices
        for(size_t i = 0; i < nbVertices; ++i) 
        {
            // a vertex index
            int index = indices[i];
            // a vertex values from it index
            float* p = &source->GetData()[index*3];
            normals[i] = gx::Vec3f(p[0], p[1], p[2]);
        }
        result->setNormals(normals);
    }

    // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = 
    // Textcoords (1st channel)

    // Repeate with texture coordinates
    source = fcdSet.GetParent()->FindSourceByType(FUDaeGeometryInput::TEXCOORD);

    // They may not be present
    if(source != NULL) 
    {
        // indices
        input = fcdSet.FindInput(FUDaeGeometryInput::TEXCOORD);
        indices = input->GetIndices();

        // allocate memory for triangles and its vertex (a triangle has 3 vertex)
        std::vector<gx::Vec3f> texCoords(nbVertices);
        int stride = source->GetStride();
        
        // 3ds max exports textures with 3 coordinates, 
        // but maya and Google Earth use 2 coordinates

        // look for vertices using indices
        for(size_t i = 0; i < nbVertices; ++i) 
        {
            // Vertex index
            int index = indices[i];

            // Vertex value from its index
            float* p = &source->GetData()[index * stride];
            texCoords[i] = gx::Vec3f(p[0], p[1], stride == 3 ? p[2] : 0.0f);
        }
        result->setTexCoords(texCoords);
    }
    
    return result;
}

// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =  

MaterialParams convertMaterial(FCDMaterial* fcdMat, 
                               std::wstring&  name)
{
    MaterialParams result;

    // to manage a problem transperencies
    //m_is_transparency_one_opaque=true;

    // Start from the default mat
    result.makeDefault();

    // set default material if necessary
    if(fcdMat == NULL) 
    {
        name = L"default";
        return result;
    }

    // if common profile does not exist, set as default material
    FCDEffect* fx = fcdMat->GetEffect();
    FCDEffectProfile* profile = fx->FindProfile(FUDaeProfileType::COMMON);

    if(profile == NULL) 
    {
        name = L"default";
        return result;
    }

    // if we arrive here, extract all information from "material"
    name = CA2T(fcdMat->GetDaeId());
    
    // copy properties of common profile
    FCDEffectStandard* stdProfile = dynamic_cast<FCDEffectStandard*>(profile);
    ASSERT(stdProfile != NULL);

    // configure alpha value in diffuse material
    result.transparency = stdProfile->GetTranslucencyFactor();

    // ambient
    result.ambientColor = Color(
        stdProfile->GetAmbientColor().x,
        stdProfile->GetAmbientColor().y,
        stdProfile->GetAmbientColor().z,
        stdProfile->GetAmbientColor().w
    );

    // diffuse component
    result.diffuseColor = Color(
        stdProfile->GetDiffuseColor().x,
        stdProfile->GetDiffuseColor().y,
        stdProfile->GetDiffuseColor().z,
        1.0 // opaque for opengl, use m_transparency on polygon::render   
    );

    // specular
    float specular_factor = stdProfile->GetSpecularFactor();
    result.specularColor = Color(
        specular_factor*stdProfile->GetSpecularColor().x,
        specular_factor*stdProfile->GetSpecularColor().y,
        specular_factor*stdProfile->GetSpecularColor().z,
        specular_factor*stdProfile->GetSpecularColor().w  
    );

    // shininess
    result.shininess = stdProfile->GetShininess() / 128.f;

    // emission
    if(stdProfile->IsEmissionFactor()) 
    {
        result.emissionColor = Color(
            stdProfile->GetEmissionFactor(),
            stdProfile->GetEmissionFactor(),
            stdProfile->GetEmissionFactor(),
            stdProfile->GetEmissionFactor()
        );
    }
    else 
    {
        result.emissionColor = Color(
            stdProfile->GetEmissionColor().x * stdProfile->GetEmissionFactor(),
            stdProfile->GetEmissionColor().y * stdProfile->GetEmissionFactor(),
            stdProfile->GetEmissionColor().z * stdProfile->GetEmissionFactor(),
            stdProfile->GetEmissionColor().w * stdProfile->GetEmissionFactor()
        );
    }


    // not used at the moment
    //transparent mode
    result.transparentMode = 
        stdProfile->GetTransparencyMode() == FCDEffectStandard::RGB_ZERO ? 
            TransparentModes::RgbZero : TransparentModes::AlphaOne;

    // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
    // textures
    
    // diffuse texture
    if(stdProfile->GetTextureCount(FUDaeTextureChannel::DIFFUSE) > 0) 
    {
        FCDTexture* texture =
            stdProfile->GetTexture(FUDaeTextureChannel::DIFFUSE, 0);
        if(texture!=NULL) 
        {
            FCDImage* image = texture->GetImage();
            if(image != NULL) 
            {
                std::wstring imageId = CA2T(image->GetDaeId().c_str());
                result.diffuseTexture = getTextureByName(imageId);
                ASSERT(result.diffuseTexture != NULL);
            }
        }
    }

    // reflective texture

    // reflective texture
    if(stdProfile->GetTextureCount(FUDaeTextureChannel::REFLECTION) > 0) 
    {
        //float r=stdProfile->GetReflectivityFactor();
        //float r=stdProfile->GetReflectivity();
        //float r2=stdProfile->GetReflectivityFactor();
        FCDTexture* texture = stdProfile->GetTexture(FUDaeTextureChannel::REFLECTION, 0);
        if(texture!=NULL) 
        {
            FCDImage* image = texture->GetImage();
            if(image!=NULL) {
//                m_texture_reflective=m_main->SearchTextureByName(image->GetDaeId().c_str());
  //              if(m_texture_reflective!=NULL)
    //                if(m_texture_reflective->getId()!=-1)
      //                  m_has_reflective_texture=true;
            }
        }
    }
    
/*
    // transparent textures
    m_has_transparent_texture=false;
    m_texture_transparent=NULL;
    image=NULL;

    //// transparent texture
    //if(stdProfile->GetTextureCount(FUDaeTextureChannel::TRANSPARENT)>0) {
    //texture=stdProfile->GetTexture(FUDaeTextureChannel::TRANSPARENT,0);
    //if(texture!=NULL) {
    //image=texture->GetImage();
    //if(image!=NULL) {
    //m_texture_transparent=m_main->SearchTextureByName(image->GetDaeId());
    //if(m_texture_transparent!=NULL)
    //if(m_texture_transparent->getId()!=-1)
    //m_has_transparent_texture=true;
    //}
    //}
    //}
    */

    return result;
}


void buildSceneGraph(FCDSceneNode* fcdNode, NodeManager& nm, Node* parent)
{
    ref<Node> node;

    FCDSceneNode* child_origin;
    //CCLNode* child_dest;
    FCDTransform*  trans_origin;

    gx::Mat4 transform(gx::eye);

    // copy node transformations
    for(int i = 0; i<(int)fcdNode->GetTransformCount(); i++) 
    {
        trans_origin = fcdNode->GetTransform(i);
        FMMatrix44 m = trans_origin->ToMatrix();
        gx::Mat4 curr;
        for(int a = 0; a < 4; ++a)
        {
            curr.get_col(a) = gx::Vec3(m[a][0], m[a][1], m[a][2]);
        }

        transform = curr * transform;
    }

    bool flagFound = false;

    // Copy node instances
    for(size_t i = 0; i < fcdNode->GetInstanceCount() && !flagFound; i++) 
    {
        flagFound=false;
        FCDEntityInstance* instance = fcdNode->GetInstance(i);
        FCDEntity* entity = instance->GetEntity();
        std::string entityId = entity->GetDaeId();
        dbg(entityId);

        // Look for this id in geo library
        for(size_t j = 0; j < m_meshes.size(); j++) 
        {
            ref<Mesh>& geo = m_meshes[j];

            // This was written during the loading phase
            std::string meshId = m_meshIds[geo.get()];

            if(meshId != entityId)
            {
                // Not what we were looking for
                continue;
            }

            // This will have us exit from both loops
            flagFound = true;

            // At this point we know it's a geometry instance, 
            // so it's safe to cast
            FCDGeometryInstance* fcdGeo = dynamic_cast<FCDGeometryInstance*>(instance);
            ASSERT(fcdGeo != NULL); // Paranoid check

            // The mesh was already created when the geometries were loaded. Now we
            // simply retrieve it from the vector where it was stored
            ref<Mesh> mesh = dyn_ptr_cast<Mesh>(geo);
            ASSERT(mesh != NULL);

            // Create a new MeshNode that will manage this mesh    
            std::auto_ptr<MeshNode> meshNode(new MeshNode(mesh));
            meshNode->setName(std::wstring(CA2T(meshId.c_str())));
            meshNode->setLocalTransform(transform);
            node = meshNode;

            // Bind a material to each polygon set in the mesh. This is tricky because, 
            // during the material loading phase, we perhaps renamed some of the materials
            // to avoid duplicates. Here we must take this renaming into account so that
            // we are able to find the appropriate materials. This involves two steps for
            // each polygon step. First, we find the original material name (the one that
            // was in the Collada file). This is stored in the "m_polyMatNames" table. 
            // Second, we find the renamed name for that original material name. This is
            // easy because have all the necessary information in the m_materialNameTable
            // table. Once we have the renamed name, we can safely use it to retrieve
            // the material instance from the material manager and bind it to the polygon
            // set in question

            for(size_t k = 0; k < mesh->getNumPolygonSets(); ++k)
            {
                PolygonSet* polySet = mesh->getPolygonSet(k);
                
                PolysToMatName::iterator it = m_polyMatNames.find(polySet);
                
                if(it != m_polyMatNames.end()) // If poly set has material
                {
                    // material name (semantic) in the "polygons" tag of the Collada file
                    std::wstring semanticName = it->second; 

                    // Retrieve a material instance bound to the given material semantic.
                    FCDMaterialInstance* fcdMatInst = 
                        fcdGeo->FindMaterialInstance(semanticName.c_str());

                    // Sanity check (if this fails it's FCOLLADA's fault not mine)
                    ASSERT(fcdMatInst->GetSemantic().c_str() == semanticName);  
                    
                    // The actual material that corresponds to the semantic name
                    FCDMaterial* fcdMat = fcdMatInst->GetMaterial();
                    
                    // This is the real material name (not the semantic name)
                    std::wstring matId = CA2T(fcdMat->GetDaeId());

                    // The material might have been renamed during the loading phase.
                    // Retrieve its final name (which might coincide with the "real"
                    // name if the material wasn't renamed
                    
                    StringToString::iterator it2 = m_materialNameTable.find(matId);
                    
                    // Translation table includes all materials, even if we don't rename them
                    ASSERT(it2 != m_materialNameTable.end()); 

                    // Final material name (coincides with original if not renamed)
                    std::wstring finalName = it2->second; 

                    // Ask manager for material instance (it has to have it because we
                    // added it during the material loading phase)
                    Material* mat = theApp.getWorld().getMaterialManager().getMaterialByName(finalName);
                    ASSERT(mat != NULL);

                    // Assign that material instance to the current polygon set
                    polySet->setMaterial(mat->getRef<Material>());
                }
            }
            
            if(parent == NULL) // Add topLevel scenetree item
            {
                nm.append(node);
            }
            else // Add child scenetree item
            {
                nm.append(parent, node);
            }
        }
/*
        // maybe this node is a light. look for this name in light library
        for(j=0; j<(int)m_ptrs_lights.size(); j++) {
            if(m_ptrs_lights[j]->GetId()==name) {
                node_dest->AddInstance(m_ptrs_lights[j]);
                // mesh found, jump to the next instance 
                // (avoid this FOR and the following FORs)
                flag_found=true;
                break;
            }
        }
        if(flag_found) continue;

        // maybe this instance is a camera. look for this name in the cameras library
        for(j=0; j<(int)m_ptrs_cameras.size(); j++) {
            if(m_ptrs_cameras[j]->GetId()==name) {
                node_dest->AddInstance(m_ptrs_cameras[j]);
                // found, jump to the next instance 
                // (avoid this FOR and the following FORs)
                flag_found=true;
                break;
            }
        }
        if(flag_found) continue;

    */
    }
    
    // CAUTION! recursive part.
    //  Create children and attach them to their parents
    for(size_t i = 0; i < fcdNode->GetChildrenCount(); ++i) 
    {
        // create a child and set up it parent
        child_origin = fcdNode->GetChild(i);

        // recursive. call myself
        buildSceneGraph(child_origin, nm, node.get());
    }
}



bool OpenColladaFile(LPCTSTR lpszPathName)
{
    // version of FCOLLADA

    // new dae file
    FCDocument* m_document = FCollada::NewTopDocument();

    // open dae file
    bool ret=FCollada::LoadDocumentFromFile(m_document,FUStringConversion::ToFString(lpszPathName) );

    if(!ret || m_document == NULL) 
    {
        return false;
    }

    // 3dsmax, maya and opengl have up axis differnt
    // with this information  we could rotate the model
    isZUp = int(m_document->GetAsset()->GetUpAxis().z) == 1;

    // The geometry library contains a list of basic geometries, which may
    // be instantiated within the scene graph and may be used by controllers.
    // COLLADA supports two geometry types: mesh and spline.    
    FCDGeometryLibrary* geolib = m_document->GetGeometryLibrary();
    
    // Copy all mess geometries objects from fcollada to our structures
    for(size_t i = 0; i < geolib->GetEntityCount(); i++) 
    { 
        // The Collada geometry object
        FCDGeometry* fcdGeo = geolib->GetEntity(i);

        // there are 3 types of geometries, nurbs, splines and meshes
        // at the moment JUST meshes, neither nurbs nor splines

        // meshes
        if(fcdGeo->IsMesh()) 
        {
            // Create a new mesh based on the collada mesh. This involves 
            // triangulating the mesh and copying it polygons by polygons
            std::auto_ptr<Mesh> mesh(convertMesh(fcdGeo->GetMesh()));
            m_meshIds[mesh.get()] = fcdGeo->GetDaeId();

            
            // Each polygon set within the mesh hast its semantic material. Store
            // each in a map so that we can retrieve them later on during while
            // constructing the scene graph. 
            for(size_t j = 0; j < mesh->getNumPolygonSets(); ++j)
            {
                m_polyMatNames[mesh->getPolygonSet(j)] = 
                    fcdGeo->GetMesh()->GetPolygons(j)->GetMaterialSemantic();
            }
            
            // Add this mesh to the list of geometries. We will retrive it from
            // there when we construct the scene graph
            m_meshes.push_back(ref<Mesh>(mesh));
            continue;
        }

        /*
        // nurbs
        if(geo->IsPSurface()) {
            m_ptr_geometry=dynamic_cast<CCLGeometry*>(new CCLSurface(geo->GetPSurface()));
            // add and look for the next geometry
            m_meshes.push_back(m_ptr_geometry);
            continue;
        }

        // splines
        if(geo->IsSpline()) {
            m_ptr_geometry=dynamic_cast<CCLGeometry*>(new CCLSpline(geo->GetSpline()));
            // add and look for the next geometry
            m_meshes.push_back(m_ptr_geometry);
            continue;
        }
        */
    }
/*
    // how many lights there are?
    FCDLightLibrary* lightlib=m_document->GetLightLibrary();
    m_num_lights=(int) lightlib->GetEntityCount();
    m_ptrs_lights.reserve(m_num_lights);

    // copy lights to my structures
    FCDLight* light;
    LightParams* m_ptr_light;
    for(int i = 0; i<m_num_lights; i++) {
        light = lightlib->GetEntity(i);

        // ambiental light
        if(light->GetLightType()==FCDLight::AMBIENT) {
            m_ptr_light=dynamic_cast<CCLLight*>(new CCLLightAmbient(light));
            // add our new light
            m_ptrs_lights.push_back(m_ptr_light);
            continue;
        }

        // spot light (luz focal)
        if(light->GetLightType()==FCDLight::SPOT) {
            m_ptr_light=dynamic_cast<CCLLight*>(new CCLLightSpot(light));
            // add our new light
            m_ptrs_lights.push_back(m_ptr_light);
            continue;
        }

        // directional  light
        if(light->GetLightType()==FCDLight::DIRECTIONAL) {
            m_ptr_light=dynamic_cast<CCLLight*>(new CCLLightDirectional(light));
            // add our new light
            m_ptrs_lights.push_back(m_ptr_light);
            continue;
        }

        // point light
        if(light->GetLightType()==FCDLight::POINT) {
            m_ptr_light=dynamic_cast<CCLLight*>(new CCLLightPoint(light));
            // add our new light
            m_ptrs_lights.push_back(m_ptr_light);
            continue;
        }
    }
*/

    // IMPORTANT. copy textures before materials because materials will call these textures
    // copy images or textures to my structures
    FCDImageLibrary* imagelib = m_document->GetImageLibrary();
    size_t nbTextures = (int)imagelib->GetEntityCount();
    m_textures.reserve(nbTextures);
    
    // Initialize DevIL. because we are going to read texture files
    ilInit();
    iluInit();

    // opengl lower coord, opposite to directx
    ilEnable(IL_ORIGIN_SET);
    ilOriginFunc(IL_ORIGIN_LOWER_LEFT); 

    // copy textures to our structures
    for(size_t i = 0; i < nbTextures; ++i) 
    {
        FCDImage* image = imagelib->GetEntity(i);
        ref<Texture> tex(convertTexture(image));
        
        std::wstring name = CA2T(image->GetDaeId().c_str());
        tex->setName(name);
        
        m_textures.push_back(tex);
    }

    // Shutdown DevIL
    ilShutDown();

    // --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --
    // copy materials of the common profile to my structures
    
    FCDMaterialLibrary* materiallib = m_document->GetMaterialLibrary();
    int nbMats = (int)materiallib->GetEntityCount();
    
    for(int i = 0; i < nbMats; i++) 
    {
        FCDMaterial* fcdMat = materiallib->GetEntity(i);
        
        std::wstring name;
        MaterialParams matParams = convertMaterial(fcdMat, name);
        ref<Material> mat(new Material);
        mat->setParams(matParams);

        // If the material name is already used, find a new name for it.
        // Keep the old name so we can make the translation when the 
        // material is bound to a mesh, during the scenegraph creation phase

        MaterialManager& mm = theApp.getWorld().getMaterialManager();
        Material* matWithSameName = mm.getMaterialByName(name);
        
        std::wstring newName;
        if(matWithSameName != NULL) // The name existed, so find a new one
        {
            newName = mm.generateNameFromPrefix(name);
        }
        else
        {
            newName = name; // No translation
        }
        m_materialNameTable[name] = newName;

        // Set the material name and register this material in the manager.
        mat->setName(newName);
        theApp.getWorld().getMaterialManager().registerMaterial(mat);
    }

    // --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --
/*
    // copy cameras to my structures
    // cameras
    FCDCameraLibrary* cameralib=m_document->GetCameraLibrary();
    m_num_cameras=(int) cameralib->GetEntityCount();
    m_ptrs_cameras.reserve(m_num_cameras);

    FCDCamera* camera;
    CCLCamera* m_ptr_camera;
    for(int i = 0; i<m_num_cameras; i++) {
        camera = cameralib->GetEntity(i);

        // perspective camera
        if(camera->IsPerspective()==true) {
            m_ptr_camera=dynamic_cast<CCLCamera*>(new CCLCameraPerspective(camera));
            // add our new camera
            m_ptrs_cameras.push_back(m_ptr_camera);
            continue;
        }

        // orthographic camera
        if(camera->IsOrthographic()==true) {
            m_ptr_camera=dynamic_cast<CCLCamera*>(new CCLCameraOrthographic(camera));
            // add our new camera
            m_ptrs_cameras.push_back(m_ptr_camera);
            continue;
        }
    }

    // extract start and end time
    m_start_time=m_document->GetStartTime();
    m_end_time=m_document->GetEndTime();

    // how many animations are there?
    FCDAnimationLibrary* animationlib=m_document->GetAnimationLibrary();
    int num_animations=(int) animationlib->GetEntityCount();

    // have we animations?
    if(num_animations>0) m_is_animated=true; else m_is_animated=false;

*/
    // scene
    FCDSceneNode* ptr_root = m_document->GetVisualSceneInstance();

    // if there are no nodes, inform about that
    if(ptr_root==NULL) 
    {
        AfxMessageBox(_T("The current scene is empty."), MB_ICONINFORMATION );
        //m_name_cameras_used_number=0;
        //SetNoCamera();
        //my_root=NULL;
        //m_ptr_scene=NULL;
        SAFE_DELETE(m_document);
        return true;
    }


    // initial configuration of the scene
    // set up scene
    buildSceneGraph(ptr_root, theApp.getWorld().getNodeManager(), NULL);
    //m_ptr_scene=new CCLScene(this, my_root);

    //// look for cameras in the scene graph
    //m_name_cameras_used_number=0;
    //LookForUsedCameras(my_root);

    //// select a camera if it exists, or none
    //// if there are cameras in the SG, then I choose the first one
    ////m_is_camera_selected=false;
    //if(m_name_cameras_used_number>0) {
    ////m_is_camera_selected=true;
    //SetCameraByName(GetCameraNameByIndex(0));
    //} else {
    //SetNoCamera(); // this is orbital camera
    //}

    
    
    // count the number of lights used, if 0, use a default light
//LookForUsedLights(my_root);

    // Everything is in my structures right now, 
    // delete fcollada because no longer it is necessary
    SAFE_DELETE(m_document);
    return true;

}


#endif